﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the GNU General Public License version 2 (GPLv2).
// See accompanying file License.txt or copy at http://phuse.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Phuse.Net.Sockets
{
    using System;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    using Phuse.UnitTesting;

    /// <summary>Tests <see cref="TcpClient"/> use cases not covered by other tests.</summary>
    [TestClass]
    public class TcpClientTest : TestBase
    {
        /// <summary>Tests constructor exceptions.</summary>
        [TestMethod]
        public void ConstructorTest()
        {
            AssertThrow<ArgumentNullException>(
                () => new TcpClient(null, IPEndPoint.MinPort, CancellationToken.None).Dispose());
            AssertThrow<ArgumentException>(
                () => new TcpClient(string.Empty, IPEndPoint.MinPort, CancellationToken.None).Dispose());
            AssertThrow<ArgumentOutOfRangeException>(
                () => ConnectToServer(IPEndPoint.MinPort - 1).Dispose(),
                () => ConnectToServer(IPEndPoint.MaxPort + 1).Dispose());
            AssertThrow<SocketException>(
                () => new TcpClient("localhost", IPEndPoint.MaxPort, CancellationToken.None).Dispose());
        }

        /// <summary>Tests the main use cases.</summary>
        [TestMethod]
        public void MainTest()
        {
            Assert.AreEqual(30000, TcpClient.ConnectTimeout);

            using (var client = ConnectToServer(119))
            {
                Assert.IsTrue(client.Connected);
                Assert.AreEqual(Timeout.Infinite, client.SendTimeout);
                Assert.AreEqual(Timeout.Infinite, client.ReceiveTimeout);
                var sendTimeout = Random.Next(5000, 10000);
                var receiveTimeout = Random.Next(5000, 10000);
                client.SendTimeout = sendTimeout;
                client.ReceiveTimeout = receiveTimeout;
                Assert.AreEqual(sendTimeout, client.SendTimeout);
                Assert.AreEqual(receiveTimeout, client.ReceiveTimeout);
                Assert.IsTrue(client.SendBufferSize > 0);
                Assert.IsTrue(client.ReceiveBufferSize > 0);

                var received = new byte[1024];
                Assert.IsTrue(client.Receive(received, 0, received.Length) > 0);
                AssertThrow<SocketException>(() => client.Receive(received, 0, received.Length));
                var sent = Encoding.UTF8.GetBytes("QUIT\r\n");
                client.Send(sent, 0, sent.Length);
                client.Dispose();
                AssertThrow<ObjectDisposedException>(() => client.Send(new byte[0], 0, 0));
            }

            TcpClient.ConnectTimeout = 0;
            Assert.AreEqual(0, TcpClient.ConnectTimeout);

            AssertThrow<SocketException>(() => ConnectToServer(119).Dispose());
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private static TcpClient ConnectToServer(int port)
        {
            return new TcpClient("news.giganews.com", port, CancellationToken.None);
        }
    }
}
